package com.jsbs.iam.user.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.jsbs.iam.common.core.dto.Result;
import com.jsbs.iam.common.core.utils.Json;
import com.jsbs.iam.common.core.utils.PageHelperTool;
import com.jsbs.iam.user.constant.RedisConstants;
import com.jsbs.iam.user.dto.ApplyConfigAddDto;
import com.jsbs.iam.user.dto.ApplyConfigDeleteDto;
import com.jsbs.iam.user.dto.ApplyConfigGetDto;
import com.jsbs.iam.user.dto.ApplyConfigSelectDto;
import com.jsbs.iam.user.entity.IamAdminRoleOrgInfo;
import com.jsbs.iam.user.entity.IamApplySystem;
import com.jsbs.iam.user.feign.ApplySystemFeign;
import com.jsbs.iam.user.feign.IdentFeignInterface;
import com.jsbs.iam.user.mapper.AdminRoleMapper;
import com.jsbs.iam.user.mapper.ApplyConfigMapper;
import com.jsbs.iam.user.mapper.OrgInfoMapper;
import com.jsbs.iam.user.mapper.UserInfoMapper;
import com.jsbs.iam.user.service.AdminRoleService;
import com.jsbs.iam.user.service.ApplyConfigService;
import com.jsbs.iam.user.vo.AdminRoleVo;
import com.jsbs.iam.user.vo.ApplyAccountVo;
import com.jsbs.iam.user.vo.IamAdminRoleApplyInfoVo;
import io.netty.util.internal.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @BelongsProject: iam
 * @BelongsPackage: com.jsbs.iam.user.service.impl
 * @Author: WangJiYuan
 * @Description: TODO
 * @Version: 2023-01-04  11:47
 */
@Service
@Slf4j
public class ApplyConfigServiceImpl implements ApplyConfigService {

    @Autowired
    private ApplyConfigMapper applyConfigMapper;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Resource
    private RedissonClient redissonClient;

    @Autowired
    private ApplySystemFeign applySystemFeign;

    @Autowired
    private UserInfoMapper userInfoMapper;

    @Autowired
    private IdentFeignInterface identFeignInterface;

    @Autowired
    private AdminRoleService adminRoleService;

    @Autowired
    private OrgInfoMapper orgInfoMapper;

    @Autowired
    private AdminRoleMapper adminRoleMapper;

    private static final String ADMIN_USER = "admin";


    /**
     * 获取应用编码
     *
     * @param prefix
     * @param numLength
     * @param companyCode
     * @return
     */
    public String getApplyCodeByRedis(String prefix, int numLength, String companyCode) {
        // 生成应用编码加锁，失效时间10分钟
        RLock lock = redissonClient.getLock(RedisConstants.APPLY_CODE_LOCK);
        String returnCode = "";
        try {
            String upperCode = "";
            //Redis中存储的key
            String key = "apply_" + prefix;
            Long size = redisTemplate.opsForList().size(key);//查找 prefix 的key值的数据长度
            if (size > 0) {//有数据
                List leve = redisTemplate.opsForList().range(key, 0, -1);//获取该key下面的所有值(-1 所有的值，；1下一个值
                upperCode = leve.get(leve.size() - 1).toString();//返回最后一个值
            }
            //判断redis中序列是否为空
            if (StringUtils.isEmpty(upperCode)) {
                //查询应用编码
                upperCode = applyConfigMapper.selectApplyId(companyCode);
            }
            int Suffix;  //后缀数字
            if (!StringUtil.isNullOrEmpty(upperCode)) { //有数据
                String sequence = upperCode.substring(prefix.length());//截取前缀开始的后面的数字
                Suffix = Integer.parseInt(sequence);
                Suffix++;//最后的序号加一
            } else {
                Suffix = 1;//没有数据
            }
            returnCode = prefix + String.format("%0" + numLength + "d", Suffix);//后缀不够numLength长，前面补充0
            redisTemplate.opsForList().rightPush(key, returnCode);//存入Redis
        } catch (Exception e) {
            log.error("Route=>ApplyConfigServiceImpl method=>getApplyCodeByRedis 应用,系统自动生成编码失败:", e);
            throw new RuntimeException("应用,系统自动生成编码异常");
        } finally {
            // 手动解锁
            if (lock.isLocked()) {
                lock.unlock();
            }
        }
        return returnCode;
    }

    @Override
    public void insetApplyData(ApplyConfigAddDto applyConfigAddDto) {
        applyConfigAddDto.setApplyCode(this.getApplyCodeByRedis("yybm", 6, applyConfigAddDto.getCompanyCode()));
        applyConfigMapper.insetApplyData(applyConfigAddDto);
    }

    @Override
    public PageInfo getApplyData(ApplyConfigSelectDto applyConfigSelectDto) {
        applyConfigSelectDto.init();
        PageHelper.startPage(applyConfigSelectDto.getCurrPage(), applyConfigSelectDto.getPageSize());
        //获取应用数据
        List<IamApplySystem> list = new ArrayList<>();
        //权限限制
        if (ADMIN_USER.equals(applyConfigSelectDto.getCreatePerson())) {
            //超管
            list = applyConfigMapper.getApplyData(applyConfigSelectDto);
        } else {
            //普管
            //获取角色应用权限
            List<IamAdminRoleApplyInfoVo> adminRoleApplyInfo = adminRoleMapper.getAdminRoleApplyInfo(applyConfigSelectDto.getAdminRoleCode(), applyConfigSelectDto.getCompanyCode());
            //角色权限下应用编码
            List<String> adminRoleApplyCodes = new ArrayList<>();
            if (CollectionUtils.isNotEmpty(adminRoleApplyInfo)) {
                if (adminRoleApplyInfo.get(0).getType() == 1) {
                    //取出所有应用编码
                    for (IamAdminRoleApplyInfoVo iamAdminRoleApplyInfo : adminRoleApplyInfo) {
                        adminRoleApplyCodes.add(iamAdminRoleApplyInfo.getApplyId().toString());
                    }
                } else {
                    //取出应用类型
                    String applyTypeCode = adminRoleApplyInfo.get(0).getApplyTypeCode();
                    //通过应用类型编码查询应用编码
                    List<String> applyCodes = applyConfigMapper.getApplyCodes(applyTypeCode, applyConfigSelectDto.getCompanyCode());
                    adminRoleApplyCodes.addAll(applyCodes);
                }
                applyConfigSelectDto.setAdminRoleApplyCodes(adminRoleApplyCodes);
            }
            //获取普通管理员的应用数据
            list = applyConfigMapper.getAdminRoleApplyData(applyConfigSelectDto);
        }
        PageInfo<IamApplySystem> page = new PageInfo<>(list);
        PageInfo<IamApplySystem> pageInfo =
                PageHelperTool.initPageInfoObj(applyConfigSelectDto.getCurrPage(), (int) page.getTotal(), applyConfigSelectDto.getPageSize(), page);
        return pageInfo;
    }

    @Override
    public void updateApplyData(ApplyConfigAddDto applyConfigAddDto) {
        applyConfigMapper.updateApplyData(applyConfigAddDto);
    }

    @Override
    @Transactional
    public void deleteApplyData(ApplyConfigDeleteDto applyConfigDeleteDto) {
        //删除应用基础数据
        applyConfigMapper.deleteApplyData(applyConfigDeleteDto);
        //通过应用查询所有菜单编码
        List<String> menuCodes = applyConfigMapper.getMenuCodes(applyConfigDeleteDto);
        applyConfigDeleteDto.setMenuCodes(menuCodes);
        //删除菜单数据
        applyConfigMapper.deleteMenuData(applyConfigDeleteDto);
        //通过菜单编码删除按钮数据
        applyConfigMapper.deleteButtonData(applyConfigDeleteDto);

        //删除应用,菜单,按钮和角色,用户组的关联关系
        Result result = applySystemFeign.deleteApplyRelation(applyConfigDeleteDto);
        log.info("远程调用auth服务,删除应用,菜单,按钮和角色,用户组的关联关系", Json.toJsonString(result));
        if (!result.isSuccess()) {
            log.error("远程调用auth服务,删除应用,菜单,按钮和角色,用户组的关联关系失败!!!", Json.toJsonString(result));
            throw new RuntimeException("远程调用auth服务,删除应用,菜单,按钮和角色,用户组的关联关系失败!!!");
        }
    }

    @Override
    public PageInfo getAccountData(ApplyConfigGetDto applyConfigGetDto) {
        applyConfigGetDto.init();
        PageHelper.startPage(applyConfigGetDto.getCurrPage(), applyConfigGetDto.getPageSize());
        //远程调用权限中心获取应用下绑定的用户数据
        Result userDataResult = applySystemFeign.getUserDataByApply(applyConfigGetDto);
        log.info("远程调用auth服务,获取应用绑定的用户", Json.toJsonString(userDataResult));
        if (!userDataResult.isSuccess()) {
            log.error("远程调用auth服务,获取应用绑定的用户!!!", Json.toJsonString(userDataResult));
            throw new RuntimeException("远程调用auth服务,获取应用绑定的用户!!!");
        }
        //取出用户数据
        List<String> userCodes = (List<String>) userDataResult.getData();
        if (CollectionUtils.isEmpty(userCodes)) {
            return null;
        }
        applyConfigGetDto.setUserCodes(userCodes);
        //筛选出有效的账号  通过对比用户数据是否在应用数据所对应的组织数据下
        //获取应用对应的组织编码
        List<String> applyOrgCodes = applyConfigMapper.getApplyOrgCodes(applyConfigGetDto);
        //有效的用户账户数据
        List<String> validUserCodes = new ArrayList<String>();
        //通过用户数据查询用户详细数据
        List<ApplyAccountVo> accountVos = applyConfigMapper.getUserInfo(applyConfigGetDto);
        //转化组织名称
        for (ApplyAccountVo applyAccountVo : accountVos) {
            String orgNameStr = "";
            //
            if (com.jsbs.iam.common.core.utils.StringUtils.isNotEmpty(applyAccountVo.getOrgCode())) {
                //判断是否为有效用户账号数据
                for (String applyOrgCode : applyOrgCodes) {
                    if (applyAccountVo.getOrgCode().contains(applyOrgCode)) {
                        String[] orgStr = applyAccountVo.getOrgCode().split(",");
                        List<String> orgCodes = Arrays.asList(orgStr);
                        //根据组织编码获取组织名称
                        List<String> orgNames = userInfoMapper.getOrgNames(orgCodes, applyConfigGetDto.getCompanyCode());
                        if (CollectionUtils.isNotEmpty(orgNames)) {
                            for (String name : orgNames) {
                                orgNameStr = orgNameStr + name + ",";
                            }
                        }
                        //根据岗位编码获取岗位名称
                        List<String> postNames = userInfoMapper.getPostNames(orgCodes, applyConfigGetDto.getCompanyCode());
                        if (CollectionUtils.isNotEmpty(postNames)) {
                            for (String name : postNames) {
                                orgNameStr = orgNameStr + name + ",";
                            }
                        }
                        applyAccountVo.setOrgName(orgNameStr);
                        //保存有效的用户数据
                        validUserCodes.add(applyAccountVo.getUserCode());
                        break;
                    }
                }
            }
        }
        //重新赋值有效的数据
        applyConfigGetDto.setUserCodes(validUserCodes);

        //普管数据权限的限制
        if (!ADMIN_USER.equals(applyConfigGetDto.getCreatePerson())) {
            //管理员组织下的用户数据
            List<String> roleOrgUserCodes = new ArrayList<>();
            //普管
            //查询角色的权限列表
            AdminRoleVo adminRoleVo = adminRoleService.queryAdminRole(applyConfigGetDto.getRoleCode(), applyConfigGetDto.getCompanyCode());
            //获取组织权限
            List<IamAdminRoleOrgInfo> orgRoleList = adminRoleVo.getOrgRoleList();
            List<String> orgRole = new ArrayList<String>();
            if (CollectionUtils.isNotEmpty(orgRoleList)) {
                if (orgRoleList.get(0).getType() == 1) {
                    //取出所有组织编码
                    for (IamAdminRoleOrgInfo iamAdminRoleOrgInfo : orgRoleList) {
                        orgRole.add(iamAdminRoleOrgInfo.getOrgCode());
                    }
                } else {
                    String orgTypeCode = orgRoleList.get(0).getOrgTypeCode();
                    //通过组织类型查询组织编码
                    orgRole = orgInfoMapper.getOrgCodesByOrgType(orgTypeCode, applyConfigGetDto.getCompanyCode());
                }
            }
            for (String orgCode : orgRole) {
                //根据组织编码查询用户数据
                List<String> orgUserCodes = userInfoMapper.getOrgUserCodes(orgCode, applyConfigGetDto.getCompanyCode());
                roleOrgUserCodes.addAll(orgUserCodes);
            }
            //去除重复数据
            roleOrgUserCodes.stream().distinct().collect(Collectors.toList());
            //找到 所有有效数据用户  和  对应角色下的用户  交集
            //对应角色下的所有有效用户数据
            List<String> roleUserCodes = roleOrgUserCodes.stream().filter(validUserCodes::contains).collect(Collectors.toList());
            //重新赋值
            applyConfigGetDto.setUserCodes(roleUserCodes);
        }

        //根据用户数据查询账号详细数据
        Result accountResult = identFeignInterface.getAccountDataByUser(applyConfigGetDto);
        log.info("远程调用ident服务,根据用户数据查询账号数据", Json.toJsonString(accountResult));
        if (!accountResult.isSuccess()) {
            log.error("远程调用ident服务,根据用户数据查询账号数据,失败!!!", Json.toJsonString(accountResult));
            throw new RuntimeException("远程调用auth服务,根据用户数据查询账号数据,失败!!!");
        }
        //取出用户账号详细数据
        List<ApplyAccountVo> applyAccountVos = (List<ApplyAccountVo>) accountResult.getData();

        //组装用户类型数据 组织名称数据
        for (ApplyAccountVo applyAccountVo : applyAccountVos) {
            for (ApplyAccountVo accountVo : accountVos) {
                if (applyAccountVo.getUserCode().equals(accountVo.getUserCode())) {
                    applyAccountVo.setUserTypeInfo(accountVo.getUserTypeInfo());
                    applyAccountVo.setOrgName(accountVo.getOrgName());
                }
            }
        }
        PageInfo<ApplyAccountVo> page = new PageInfo<>(applyAccountVos);
        PageInfo<ApplyAccountVo> pageInfo =
                PageHelperTool.initPageInfoObj(applyConfigGetDto.getCurrPage(), (int) page.getTotal(), applyConfigGetDto.getPageSize(), page);
        return pageInfo;
    }
}
